﻿#include "FITKAFLRMesherDriver.h"

#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Interface/FITKInterfaceModel/FITKAbstractGeoModel.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKGeoCommandList.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKAbsGeoCommand.h"
#include "FITK_Component/FITKGeoCompOCC/FITKAbstractOCCModel.h"
#include "FITK_Kernel/FITKAppFramework/FITKComponents.h"
#include "FITK_Kernel/FITKCore/FITKDirFileTools.h"
#include "FITK_Interface/FITKInterfaceFlowOF/FITKOFGeometryData.h"
#include "FITK_Component/FITKAFLRDriver/FITKAFLRInputInfo.h"
#include "FITK_Kernel/FITKAppFramework/FITKProgramTaskManager.h"
#include "FITK_Kernel/FITKAppFramework/FITKExecProgramDriver.h"
#include <QApplication>

#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKGeoCommandList.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKAbsGeoCommand.h"
#include "FITK_Interface/FITKInterfaceFlowOF/FITKOFGeometryData.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKAbsGeoShapeAgent.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKGeometryMeshVS.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKGeometryMeshEntity.h"

#include "FITK_Component/FITKMeshGenAFLR/FITKAFLRSurfaceMeshModel.h"
#include "FITK_Kernel/FITKCore/FITKDataRepo.h"
#include "FITK_Interface/FITKInterfaceMeshGen/FITKMeshGenInterface.h"
#include "FITK_Component/FITKMeshGenAFLR/FITKAFLRSurfaceMeshModel.h"

#include "FITK_Interface/FITKInterfaceGeometry/FITKAbsVirtualTopoMapper.h"
#include "FITK_Kernel/FITKAppFramework/FITKMessage.h"

#include "FITK_Interface/FITKInterfaceGeometry/FITKGeoInterfaceFactory.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKAbsGeoModelExport.h"

#include <QDir>
#include <QTextStream>
#include <QVector3D>
#include <QDebug>


namespace AFLR
{
    void FITKAFLRMesherDriver::startMesher(QStringList info /*= QStringList()*/)
    {
		_mf = Interface::FITKMeshGenInterface::getInstance();
		_surfaceMeshModel = dynamic_cast<AFLR::FITKAFLRSurfaceMeshModel*>(_mf->getGlobalMeshSizeInfo());

		//在此之前，需设置AFLR的工作路径
		QString aflr4path = getValue("AFLR").toString();
		if (!Core::CreateDir(aflr4path)) return;

		Interface::FITKOFGeometryData* geometryData = FITKAPP->getGlobalData()->getGeometryData<Interface::FITKOFGeometryData>();

		if (geometryData == nullptr)
		{
			return;
		}
		Interface::FITKAbsGeoCommand* model = geometryData->getDataByIndex(0);

		_stlFile = model->getDataObjectName() +"_1";
		_stpFile = model->getDataObjectName() + "_1";
		_surfFile = model->getDataObjectName();
		_urgidFile = model->getDataObjectName();
		_foamFile = model->getDataObjectName();

		QStringList extensions = { _stlFile+".stp",".log", ".surf", ".ugrid", ".egads", ".arg" };
		removeFilesByExtension(aflr4path,extensions);
	

		 // 工作路径
		QString path = getValue("AFLR").toString();
		if (path.isEmpty() || !Core::CreateDir(path)) return;

		// 写出STL文件
		QString stlFolder = path + "/constant/geometry";
		Core::CreateDir(stlFolder);

		// 写出为stp文件
		Interface::FITKInterfaceGeometryFactory* fac = Interface::FITKInterfaceGeometryFactory::getInstance();
		if (!fac)
		{
			return;
		}

		Interface::FITKAbsGeoModelExport* exportCmd = fac->createCommandT<Interface::FITKAbsGeoModelExport>
			(Interface::FITKGeoEnum::FITKGeometryComType::FGTExport);
		if (!exportCmd)
		{
			return;
		}

		exportCmd->setFileName(aflr4path + "/" + _stpFile + ".stp");
		bool flag = exportCmd->update();
		if (!flag)
		{
			return;
		}

		startSurfaceMeshing();
    }

    void FITKAFLRMesherDriver::stopMesher(QStringList info /*= QStringList()*/)
    {
        //todo
    }

	void FITKAFLRMesherDriver::startSurfaceMeshing()
	{
		auto proGramManager = FITKAPP->getProgramTaskManager();
		if (proGramManager == nullptr) return; 

		QStringList AFLR4SufrMesh = {};
		//添加程序参数 输入文件
		AFLR4SufrMesh.append("-i");
		AFLR4SufrMesh.append(_stpFile +".stp");

		//添加程序参数 输出文件
		AFLR4SufrMesh.append("-o");
		AFLR4SufrMesh.append(_surfFile + ".surf");

		//添加程序参数全局引用长度ref_len 及其数值
		AFLR4SufrMesh.append("ref_len");
		AFLR4SufrMesh.append(QString::number(_surfaceMeshModel->getGlobalSize()));

		//添加程序参数远场表面ff_ids 及其远场表面网格加密系数cdfr

		//获取模型ID
		 int farfieldmodelID = _surfaceMeshModel->getGeoIndexFarFidldId();
		 // 获取远场表面面组id
		int faifieldID = _surfaceMeshModel->getFarfieldId();

		// 获取 远场表面ID
		QString newFarfieldID = setFaceID(farfieldmodelID, faifieldID);

		if (!newFarfieldID.isEmpty())
		{
			AFLR4SufrMesh.append("ff_ids");
			AFLR4SufrMesh.append(newFarfieldID);

			AFLR4SufrMesh.append("ff_cdfr");
			AFLR4SufrMesh.append(QString::number(_surfaceMeshModel->getFarfieldRefinementFactor()));
		}

		// 获取指定面 指定边加密的表面ID
		QVector<LocalRefinement> localRefinement = _surfaceMeshModel->getTableWidgetValue();
		QString localFaceID{};
		QString localFaceFactor{};
		QString localEdgeID{};
		QString localEdgeFactor{};
		for (const LocalRefinement& refinement : localRefinement)
		{
			if (refinement.isCheck)
			{
				if (refinement.encryptType == SurfaceEncryption)
				{
					int localFaceModelID = refinement.geoIndex;
					int localFaceGroupID = refinement.faceGroup; 
					localFaceID.append(setFaceID(localFaceModelID, localFaceGroupID));
					localFaceFactor.append(generaterRefinementFactors(setFaceID(localFaceModelID, localFaceGroupID),refinement.EncryptionFactor));
				}else if (refinement.encryptType == EdgeEncryption)
				{
					int localEdgeModelID = refinement.geoIndex;
					int localEdgeGroupID = refinement.faceGroup;
					localEdgeID.append(setFaceID(localEdgeModelID, localEdgeGroupID));
					localEdgeFactor.append(generaterRefinementFactors(setFaceID(localEdgeModelID, localEdgeGroupID),refinement.EncryptionFactor));
				}else if (refinement.encryptType == AllEncryption)
				{
					int localAllModelID = refinement.geoIndex;
					int localAllGroupID = refinement.faceGroup;
					localFaceID.append(setFaceID(localAllModelID, localAllGroupID));
					localEdgeID.append(setFaceID(localAllModelID, localAllGroupID));
					localFaceFactor.append(generaterRefinementFactors(setFaceID(localAllModelID, localAllGroupID), refinement.EncryptionFactor));
					localEdgeFactor.append(generaterRefinementFactors(setFaceID(localAllModelID, localAllGroupID), refinement.EncryptionFactor));
				}
			}
		}

		if (!localFaceID.isEmpty())
		{
			//添加程序参数指定面加密 及其加密系数
			AFLR4SufrMesh.append("sf_ids");
			AFLR4SufrMesh.append(localFaceID);
			AFLR4SufrMesh.append("sf_list");
			AFLR4SufrMesh.append(localFaceFactor);
		}

		if (!localEdgeID.isEmpty())
		{
			//添加程序参数指定边加密 及其加密系数
			AFLR4SufrMesh.append("erw_ids");
			AFLR4SufrMesh.append(localEdgeID);
			AFLR4SufrMesh.append("erw_list");
			AFLR4SufrMesh.append(localEdgeFactor);
		}

		//添加程序参数日志打印信息
		AFLR4SufrMesh.append("-log");
	

		AppFrame::FITKProgramInputInfo* inputInfo = new AFLRDriver::FITKAFLRInputInfo();
		inputInfo->setArgs(AFLR4SufrMesh);

		auto driver = proGramManager->createProgram(1, "FITKAFLRMeshDriver", inputInfo);
		auto execDriver = dynamic_cast<AppFrame::FITKExecProgramDriver *>(driver);
		if (nullptr != execDriver)
		{
			QObject::connect(driver, SIGNAL(sig_Finish()), this, SLOT(startVolumeMeshing()));
			execDriver->setWorkingDirectory(getValue("AFLR").toString());
			execDriver->setExecProgram(getValue("AFLR").toString() + "/aflr4.exe");
			execDriver->start();


		}
	}

	void FITKAFLRMesherDriver::startVolumeMeshing()
	{
		if (!checkFileAndExecute(_surfFile + ".surf"))
		{
			AppFrame::FITKMessageError(QString("The file %1.surf does not exist.").arg(_surfFile));
			return;
		}
		// 执行AFLR3生成体网格程序
		auto proGramManager = FITKAPP->getProgramTaskManager();
		if (proGramManager == nullptr) return;

		// 设置体网格参数信息
		QStringList AFLR3VolumeMesh = {};

		//添加程序参数 输入文件
		AFLR3VolumeMesh.append("-i");
		AFLR3VolumeMesh.append(_surfFile + ".surf");

		if (_surfaceMeshModel->getGenerateBL())
		{
			//添加程序参数 生成边界层
			AFLR::BLGridType gridtype = _surfaceMeshModel->getBLGridType();
			switch (gridtype)
			{
			case AFLR::BLGridType::Basic:
				AFLR3VolumeMesh.append("-bl");
				break;
			case AFLR::BLGridType::Prisms:
				AFLR3VolumeMesh.append("-blc");
				break;
			case AFLR::BLGridType::SplitHex:
				AFLR3VolumeMesh.append("-blc2");
				break;
			case AFLR::BLGridType::FullHex:
				AFLR3VolumeMesh.append("-blc3");
				break;
			default:
				break;
			}

			//添加程序参数 初始法向间距-blds
			AFLR3VolumeMesh.append("-blds");
			AFLR3VolumeMesh.append(QString::number(_surfaceMeshModel->getFirstLayerThickness()));

			//添加程序参数 几何增长率-blr
			AFLR3VolumeMesh.append("-blr");
			AFLR3VolumeMesh.append(QString::number(_surfaceMeshModel->getGeometricGrowthRate()));


			int BLModelID = _surfaceMeshModel->getGeoIndexBoundaryLayerFaces();
			int BLFaceGroupID = _surfaceMeshModel->getBoundaryLayerFaces();
			QString BLID = setFaceID(BLModelID, BLFaceGroupID);
			QString BLFlag = generaterRefinementFactors(BLID, -1);
			QString BLNumber = generaterRefinementFactors(BLID, _surfaceMeshModel->getLayers());

			int INSModelID = _surfaceMeshModel->getGeoIndexIntersectingFaces();
			int INSFaceGroupID = _surfaceMeshModel->getIntersectingFaces();
			QString INSID = setFaceID(INSModelID, INSFaceGroupID);
			QString InsFlag = generaterRefinementFactors(INSID, 2);
			QString Ins_BLNumber = generaterRefinementFactors(INSID, 0);

			QString BC_ID = BLID + INSID;
			QString BC_Flags = BLFlag + InsFlag;
			QString BL_Numbers = BLNumber + Ins_BLNumber;
			//添加程序参数 网格BC标志列表Grid_BC_Flag和ID列表BC_IDs

			if (!BC_ID.isEmpty() || !BC_Flags.isEmpty())
			{
				AFLR3VolumeMesh.append("Grid_BC_Flag");
				AFLR3VolumeMesh.append(BC_Flags);
				AFLR3VolumeMesh.append("BC_IDs");
				AFLR3VolumeMesh.append(BC_ID);

				//添加程序参数 边界层数量限制
				AFLR3VolumeMesh.append("Number_of_BLs");
				AFLR3VolumeMesh.append(BL_Numbers);
			}

			//添加程序参数 边界层厚度
			AFLR3VolumeMesh.append("-bldel");
			AFLR3VolumeMesh.append(QString::number(_surfaceMeshModel->getBLThickness()));
		}

		//添加程序参数 日志打印信息
		AFLR3VolumeMesh.append("-log");


		auto inputInfo = new AFLRDriver::FITKAFLRInputInfo();
		inputInfo->setArgs(AFLR3VolumeMesh);

		auto driver = proGramManager->createProgram(1, "FITKAFLRMeshDriver", inputInfo);
		auto execDriver = dynamic_cast<AppFrame::FITKExecProgramDriver *>(driver);
		if (nullptr != execDriver)
		{
			QObject::connect(driver, SIGNAL(sig_Finish()), this, SLOT(startConversion()));
			execDriver->setWorkingDirectory(getValue("AFLR").toString());
			execDriver->setExecProgram(getValue("AFLR").toString() +"/aflr3.exe");
			execDriver->start();
		}
	}

	void FITKAFLRMesherDriver::startConversion()
	{
		if (!checkFileAndExecute(_surfFile + ".b8.ugrid"))
		{
			AppFrame::FITKMessageError(QString("The file %1.b8.ugrid does not exist.").arg(_urgidFile));
			return;
		}

		// 设置转换文件参数信息
		QStringList AFLR3Convert{};
		AFLR3Convert.append("-convert");
		
		//添加程序参数 输入文件
		AFLR3Convert.append("-i");
		AFLR3Convert.append(_urgidFile + ".b8.ugrid");

		//添加程序参数 输出文件
		AFLR3Convert.append("-o");
		AFLR3Convert.append(_foamFile + ".foam");

		auto inputInfo = new AFLRDriver::FITKAFLRInputInfo();
		inputInfo->setArgs(AFLR3Convert);

		// 执行AFLR3转换文件网格程序
		auto proGramManager = FITKAPP->getProgramTaskManager();
		auto driver = proGramManager->createProgram(1, "FITKAFLRMeshDriver", inputInfo);
		auto execDriver = dynamic_cast<AppFrame::FITKExecProgramDriver *>(driver);
		if (nullptr != execDriver)
		{
			QObject::connect(driver, SIGNAL(sig_Finish()), this, SIGNAL(mesherFinished()));
			execDriver->setWorkingDirectory(getValue("AFLR").toString());
			execDriver->setExecProgram(getValue("AFLR").toString() + "/aflr3.exe");
			execDriver->start();
		}
	}

	bool FITKAFLRMesherDriver::writeSTL(QString fileName)
	{
		//获取所有几何模型的数据
		Interface::FITKOFGeometryData* geometryData = FITKAPP->getGlobalData()->getGeometryData<Interface::FITKOFGeometryData>();
		//统计几何模型的数量
		int nModel = geometryData->getDataCount();

		//写入STL文件
		QFile file(fileName);
		if (!file.open(QIODevice::WriteOnly))
		{
			return false;
		}

		QTextStream stream(&file);
		
		int sum = 0;
        int faceIndex = 0;
		for (int i = 0; i < nModel; i++)
		{
			//依次获取每一个模型
			Interface::FITKAbsGeoCommand* model = geometryData->getDataByIndex(i);
			if (model != nullptr)
			{
				//获取该模型的所有面
				Interface::FITKGeometryMeshVS* meshVS = model->getShapeAgent()->getMeshVS();

				Interface::FITKVirtualTopoManager* vtmanager = model->getShapeAgent()->getVirtualTopoManager();

				if (!meshVS || !vtmanager)
				{
					return false;
				}
				 
				Interface::FITKShapeVirtualTopoManager* faceMgr = vtmanager->getShapeVirtualTopoManager(Interface::FITKGeoEnum::VTopoShapeType::VSFace);
				if (!faceMgr)
				{
					return false;
				}

				// 获取该模型的所有面数据。
				const QHash<int, Interface::FITKGeoMeshVSFaceEntity*> faceHash = meshVS->getFaceItems();

				// 遍历所有面写入STL文件。
				QHashIterator<int, Interface::FITKGeoMeshVSFaceEntity*> iter(faceHash);

				while (iter.hasNext())
				{
					iter.next();

					//int meshFaceId = iter.key();
					//Interface::FITKAbsVirtualTopo* faceTopo = faceMgr->getDataByID(meshFaceId);
					//if (!faceTopo)
					//{
					//	continue;
					//}

					// int faceIndex = faceTopo->getIndexLabel();

					Interface::FITKGeoMeshVSFaceEntity* face = iter.value();

					// 写入面起始标题行。
					stream << "solid " << QString("face_%1").arg(faceIndex) << "\n";

					// 获取属于面的所有点数据。
					const QList<Interface::FITKGeoMeshVSPt*> & facePoints = face->getPoints();

					// 获取三角面片。
					const QList<Interface::FITKGeoMeshVSTri*> & tris = face->getTriangles();

					for (Interface::FITKGeoMeshVSTri* tri : tris)
					{
						// 获取三角面片节点索引。
						const int* nodes = tri->getNode();

						// 获取三角面片节点。
						Interface::FITKGeoMeshVSPt* pt1 = facePoints[nodes[0]];
						Interface::FITKGeoMeshVSPt* pt2 = facePoints[nodes[1]];
						Interface::FITKGeoMeshVSPt* pt3 = facePoints[nodes[2]];

						// 计算三角面片法向。
						QList<QVector3D> facePointsPos;
						double nor3[3]{ 0., 0., 0. };
						facePointsPos.push_back(QVector3D(pt1->x(), pt1->y(), pt1->z()));
						facePointsPos.push_back(QVector3D(pt2->x(), pt2->y(), pt2->z()));
						facePointsPos.push_back(QVector3D(pt3->x(), pt3->y(), pt3->z()));
						Interface::FITKAbsGeoShapeAgent::GetFaceNormal(facePointsPos, nor3);

						// 写入三角面片法向。
						stream << "    facet normal " << nor3[0] << " " << nor3[1] << " " << nor3[2] << "\n";

						// 依次写入面片节点坐标。
						stream << "        outer loop\n";
						stream << "            vertex " << pt1->x() << " " << pt1->y() << " " << pt1->z() << "\n";
						stream << "            vertex " << pt2->x() << " " << pt2->y() << " " << pt2->z() << "\n";
						stream << "            vertex " << pt3->x() << " " << pt3->y() << " " << pt3->z() << "\n";
						stream << "        endloop\n";

						// 写入三角面片结束标识。
						stream << "    endfacet\n";
					}

					// 写入分组结束标识。
					stream << "endsolid " << QString("face_%1").arg(faceIndex) << "\n";

					faceIndex++;
				}

				int count = faceHash.count();
				sum += count;
			}
		}
		file.close();

		return true;

	}


	QString FITKAFLRMesherDriver::setFaceID(int modelID, int faceGroupID)
	{
		Interface::FITKOFGeometryData* GeometryData = FITKAPP->getGlobalData()->getGeometryData<Interface::FITKOFGeometryData>();

		if (GeometryData == nullptr)
		{
			return QString();
		}

		if (modelID < 0 || faceGroupID < 0)
		{
			return QString();
		}

		Interface::FITKAbsGeoCommand* model = GeometryData->getDataByID(modelID);
		if (!model)
		{
			return QString();
		}

		int modelIndex = GeometryData->getDataIndex(model);

		Interface::FITKVirtualTopoManager* vtmanager = model->getShapeAgent()->getVirtualTopoManager();
        Interface::FITKGeometryMeshVS* meshVS = model->getShapeAgent()->getMeshVS();
		if (!vtmanager || !meshVS)
		{
			return false;
		}

        QHash<int, Interface::FITKGeoMeshVSFaceEntity*> faces = meshVS->getFaceItems();
        QList<int> faceItemIds = faces.keys();

		Interface::FITKShapeVirtualTopoManager* faceMgr = vtmanager->getShapeVirtualTopoManager(Interface::FITKGeoEnum::VTopoShapeType::VSFace);
		if (!faceMgr)
		{
			return false;
		}

		int sum = 0;
		//统计当前模型之前的模型面的总数量
		for (int i = 0; i < modelIndex; i++)
		{
			Interface::FITKAbsGeoShapeAgent* GeoShapeAgent = GeometryData->getDataByIndex(i)->getShapeAgent();
			if (GeoShapeAgent == nullptr)
			{
				return QString();
			}

			const QHash<int, Interface::FITKGeoMeshVSFaceEntity*> faceHash = GeoShapeAgent->getMeshVS()->getFaceItems();

			int count = faceHash.count();
			sum += count;
		}

		QList<int> newFaceGroupID = model->getShapeAgent()
            ->getGeoComponentManager()->getDataByID(faceGroupID)->getMember();
		if (newFaceGroupID.size() == 0)
		{
			return QString();
		}


		QStringList faceIDList;
		for (const int & faceId : newFaceGroupID) {
			Interface::FITKAbsVirtualTopo* faceTopo = faceMgr->getDataByID(faceId);

			if (!faceTopo)
			{
				continue;
			}
			int faceIndex = faceTopo->getIndexLabel() + 1;

			faceIndex += sum;
			faceIDList.push_back(QString::number(faceIndex));

            //int indexOfFace = faceItemIds.indexOf(faceId) + sum;
            //faceIDList.push_back(QString::number(indexOfFace));
		}

		//QString result;
		//for (int id : faceID) {
		//	result += QString::number(id) + ",";
		//}
		return faceIDList.join(",") + ",";
	}

	QString FITKAFLRMesherDriver::generaterRefinementFactors(const QString & faceIDs, double encryptionFactor)
	{
		// 分割QString来获取单独的ID
		QStringList idList = faceIDs.split(",", QString::SkipEmptyParts);
		QStringList factorList;

		// 为每个ID添加相应的加密系数到QStringList中，每个系数后都加逗号
		for (int i = 0; i < idList.size(); ++i) {
			factorList.append(QString::number(encryptionFactor) + ",");
		}

		// 使用join函数将QStringList转换为一个QString
		QString result = factorList.join("");
		return result;
	}

	void FITKAFLRMesherDriver::removeFilesByExtension(const QString & folderPath, const QStringList & extensions)
	{
		QDir directory(folderPath);
		if (!directory.exists()) {
			qDebug() << "Directory does not exist.";
			return;
		}

		// 设置过滤器查找指定扩展名的文件
		QStringList filters;
		for (const QString &ext : extensions) {
			filters << "*" + ext;
		}
		directory.setNameFilters(filters);
		directory.setFilter(QDir::Files | QDir::NoDotAndDotDot);

		// 列出所有符合条件的文件并删除
		QStringList fileNames = directory.entryList();
		for (const QString &file : fileNames) {
			QFile::remove(directory.filePath(file));
			qDebug() << "Deleted:" << directory.filePath(file);
		}
	}
	bool FITKAFLRMesherDriver::checkFileAndExecute(const QString & fileName)
	{
		QString filePath = getValue("AFLR").toString() + "/" +fileName;
		// 检查文件是否存在
		if (!QFile::exists(filePath)) {
			qDebug() << "文件不存在：" << filePath;
			return false;  
		}
		return true;
	}
}



